using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.Specialized;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows.Threading;

using Yorrick.FlickrMetadataSynchr.Events;
using System.Threading;

namespace Yorrick.FlickrMetadataSynchr.Log
{
   /// <summary>
   /// Class that collects all activity messages that are traced.
   /// </summary>
   /// <remarks>This class needs a <see cref="Dispatcher"/> because <see cref="ObservableCollection"/> should only be modified from the 
   /// dispatcher thread when they are databound.</remarks>
   internal class ActivityCollector : IActivityListener
   {
      #region Private static field
      /// <summary>
      /// Singleton instance.
      /// </summary>
      private static ActivityCollector _singleton;
      #endregion

      #region Private fields
      /// <summary>
      /// The list of messages.
      /// </summary>
      private ObservableCollection<ActivityItem> _messages = new ObservableCollection<ActivityItem>();

      /// <summary>
      /// The dispatcher to use for synchronization.
      /// </summary>
      private Dispatcher _dispatcher;
      #endregion

      #region Public property
      /// <summary>
      /// Gets the collection of messages.
      /// </summary>
      public ObservableCollection<ActivityItem> Messages
      {
         get
         {
            return _messages;
         }
      }
      #endregion

      #region Public methods
      /// <summary>
      /// Gets the <see cref="ActivityCollector"/> singleton instance.
      /// </summary>
      /// <exception cref="InvalidOperationException">If the singleton has not been created first.</exception>
      public static ActivityCollector Singleton
      {
         get
         {
            if (_singleton == null)
            {
               throw new InvalidOperationException("Singleton should be created first.");  
            }

            return _singleton;
         }
      }

      /// <summary>
      /// Creates the singleton instance.
      /// </summary>
      /// <param name="dispatcher">The dispatcher that should be used.</param>
      public static void CreateSingleton(Dispatcher dispatcher)
      {
         if (_singleton != null)
         {
            throw new InvalidOperationException("Singleton has already been created.");
         }

         if (dispatcher == null)
         {
            throw new ArgumentNullException("dispatcher");
         }
         
         _singleton = new ActivityCollector(dispatcher);
      }
      #endregion

      #region Constructor
      /// <summary>
      /// Private constructor
      /// </summary>
      private ActivityCollector(Dispatcher dispatcher)
      {
         _dispatcher = dispatcher;
      }
      #endregion

      #region IActivityListener Members
      /// <summary>
      /// Adds the trace message to the list of messages.
      /// </summary>
      /// <param name="message"></param>
      /// <param name="messageType">The type of event.</param>
      /// <remarks>This method uses to dispatcher to that any change notifications are raised on the correct thread.</remarks>
      public void TraceActivity(string message, TraceEventType messageType)
      {
         _dispatcher.BeginInvoke(DispatcherPriority.DataBind,
            (NoArgsDelegate)delegate
            {
               _messages.Insert(0, new ActivityItem(message, messageType));
            });
      }
      #endregion
   }
}
